package com.wei.file.controller;

import com.wei.file.model.*;
import com.wei.file.serve.CodeTypeParse;
import com.wei.file.serve.FileService;
import com.wei.file.serve.RecycleService;
import com.wei.file.utils.FileUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@RestController
public class FileUploadController {
    /**
     * 实现文件的上传
     */
    @Value("${upload.url}")
    private String basePath;

    /**
     * 创建文件夹权限
     */
    @Value("${upload.mkdir}")
    private Boolean mkdir;

    @Value("${upload.secret-key}")
    private String autoSecretKey;


    private final FileService fileService = FileService.create();


    private final RecycleService recycleService;

    final
    CodeTypeParse codeTypeParse;

    public FileUploadController(RecycleService recycleService, CodeTypeParse codeTypeParse) {
        this.recycleService = recycleService;
        this.codeTypeParse = codeTypeParse;
    }


    private String createDownLink(File file) {
        String key = UUID.randomUUID().toString();
        String path = file.getPath();
        filePathMap.put(key, new FilePathModel(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24), path));
        createCount++;
        if (createCount >= 100) {
            cleanLink();
            createCount = 0;
        }
        return "/download/" + key;
    }

    private int createCount = 0;

    /**
     * key:uuid
     * value:filePath
     */
    private final Map<String, FilePathModel> filePathMap = new HashMap<>();

    private void cleanLink() {
        Iterator<Map.Entry<String, FilePathModel>> iterator = filePathMap.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, FilePathModel> entry = iterator.next();
            if (System.currentTimeMillis() > entry.getValue().getOverdue().getTime()) {
                iterator.remove();
            }
        }
    }

    @PostMapping(value = "/up_data")
    public String up_data(@RequestParam("multipartFile") MultipartFile multipartFile,
                          @RequestParam("path") String path,
                          @RequestParam(value = "secretKey", required = false) String secretKey) throws IOException {
        if (!isAuth(secretKey)) {
            return "请先获取权限";
        }

        if (path == null) {
            path = "/";
        }
        /*
          上传文件不为空
         */
        if (multipartFile.isEmpty()) {
            return "上传失败！文件不为空";
        }

        path = Paths.get(basePath, path).toString();
        if (recycleService.existsAbsFile(path)) {
            return "无法覆盖回收站内的文件，请等待回收站清理";
        }
        if (!(new File(path).isDirectory())) {
            return "路径不存在！！";
        }
//      System.out.println(path);
        /*
          上传位置
         */
        multipartFile.transferTo(new File(Paths.get(path, multipartFile.getOriginalFilename()).toString()));
//        String success = "收到文件" + multipartFile.getOriginalFilename();
//        long fileSize = multipartFile.getSize();
//        double fileKb = fileSize / 1024.0;
//        String size = "文件大小: " + String.format("%.2f", fileKb) + " KB";
//        String type = "类型: " + multipartFile.getContentType();
//        String[] arr = {success, size, type};
//        for (String s : arr) {
//            System.out.println(s);
//        }
        return "文件上传成功！";
    }

    /**
     * 文件是否存在
     *
     * @param model
     * @return
     */
    @PostMapping("/exists")
    private R existsFile(@RequestBody PathModel model) {
        String path = model.getPath();
        if (path == null) {
            path = "/";
        }

        path = Paths.get(basePath, path).toString();
        if (recycleService.existsAbsFile(path)) {
            return R.err("文件已存在，请等待回收站清理");
        }
        return R.success(new File(path).exists());
    }

    /**
     * 获取列表
     */
    @PostMapping("/list")
    public R getList(@RequestBody PathModel model) {

        if (StringUtils.isEmpty(model.getPath())) {
            model.setPath("/");
        }
        File folder = new File(Paths.get(basePath, model.getPath()).toString());
        if (!folder.exists()) {
            return R.err("路径错误");
        }
        File[] files = folder.listFiles();
        List<Object> list = new ArrayList<>(files == null ? 1 : files.length);
        ;
        if (files != null) {
            for (var item : files) {
                if (item.isHidden() || fileService.isLink(item)) {//不展示隐藏文件和快捷方式
                    continue;
                }
                if (recycleService.existsAbsFile(item.getPath())) {//回收站的文件
                    continue;
                }
                list.add(new FileItem(item, createDownLink(item)));
            }
        }
        return R.success(list);
    }


    /**
     * 创建文件夹
     */
    @PostMapping("mkdir")
    private R requestMkdir(@RequestBody MkdirModel model) {
        if (!isAuth(model.getSecretKey())) {
            return R.err("请先获取权限");
        }
        if (!mkdir) {
            return R.err("没有权限创建文件夹");
        }
        if (model.getPath() == null) {
            return R.err("path不能为空");
        }
        if (model.getFolder() == null) {
            return R.err("folder不能为空");
        }
        String path = Paths.get(basePath, model.getPath()).toString();
        File folder = new File(path);
        if (!folder.exists()) {
            return R.err("路径错误");
        }
        if (recycleService.existsAbsFile(path))
            return R.err("文件已存在，请等待清理回收站清理");

        File[] files = folder.listFiles();
        if (files != null) {
            for (var file : files) {
                if (file.exists() && file.getName().equals(model.getFolder())) {
                    return R.err("文件或文件夹已存在");
                }
            }
        }
        path = Paths.get(path, model.getFolder()).toString();
        if (recycleService.existsAbsFile(path))
            return R.err("文件已存在，请等待清理回收站清理");
        boolean flag = new File(path).mkdir();
        if (!flag) {
            return R.err("创建失败（未知原因）");
        }
        return R.success("创建成功");

    }

    @PostMapping("rename")
    private R requestRename(@RequestBody RenameModel model) {
        if (!isAuth(model.getSecretKey())) {
            return R.err("请先获取权限");
        }
        if (model.getPath() == null) return R.err("path不能为空");
        if (model.getNewName() == null) return R.err("newName不能为空");
        if (model.getOldName() == null) return R.err("oldName不能为空");
        Path oldFilePath = Paths.get(basePath, model.getPath(), model.getOldName());
        Path newFilePath = Paths.get(basePath, model.getPath(), model.getNewName());
        if (!Files.exists(oldFilePath)) {
            return R.err("目标文件不存在");
        }
        if (Files.exists(newFilePath)) {
            return R.err("文件已存在");
        }
        if (recycleService.existsAbsFile(oldFilePath.toString())) {
            return R.err("目标文件在回收站，无法重命名");
        }
        if (recycleService.existsAbsFile(newFilePath.toString())) {
            return R.err("文件已存在");
        }
        boolean flag = oldFilePath.toFile().renameTo(newFilePath.toFile());
        if (!flag) {
            return R.err("重命名失败（可能有其他程序正在访问）");
        }
        return R.success("重命名成功");

    }

    @RequestMapping("/download/{k}")
    public Object download(HttpServletResponse response, HttpServletRequest request, @PathVariable String k) {
        FilePathModel filePathModel = filePathMap.get(k);
        if (filePathModel == null) {
            return "文件不存在";
        }
        String path = filePathModel.getPath();
        if (recycleService.existsAbsFile(path)) {
            return "无法下载，文件在回收站中";
        }
        File file = new File(path);
        if (!file.isFile()) {
            return "文件不存在";
        }
        FileUtils.httpWrite(file, response, request, true);

        return null;
    }


    @RequestMapping("/preview/{k}")
    public Object preview(HttpServletResponse response, HttpServletRequest request, @PathVariable String k) {
        FilePathModel filePathModel = filePathMap.get(k);
        if (filePathModel == null) {
            return "文件不存在";
        }
        String path = filePathModel.getPath();
        if (recycleService.existsAbsFile(path)) {
            return "无法预览，文件在回收站中";
        }
        File file = new File(path);
        if (!file.isFile()) {
            return "文件不存在";
        }
        FileUtils.httpWrite(file, response, request, false);
        return null;
    }


    /**
     * @param k          文件uuid
     * @param charsetStr 解码方式
     * @return
     */
    @GetMapping(value = "previewCode/{k}")
    public ModelAndView previewCode(@PathVariable String k, @RequestParam(value = "charset", required = false) String charsetStr) {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("codePreview");
        if (charsetStr == null)
            charsetStr = "UTF_8";
        FilePathModel filePathModel = filePathMap.get(k);
        if (filePathModel == null) {
            return error("文件不存在");
        }
        String path = filePathModel.getPath();
        if (recycleService.existsAbsFile(path)) {
            return error("无法预览，文件在回收站中");
        }
        File file = new File(path);
        if (!file.isFile()) {
            return error("文件不存在");
        }
//        不能大于 5M
        if (file.length() > 1024 * 1024 * 5) {
            return error("文件过大,无法预览");
        }
        Path path1 = Paths.get(file.getPath());
        FileParseResult fpr;
        try {
            fpr = fileService.readFileString(path1, charsetStr);
        } catch (RuntimeException e) {
            return error(e.getMessage());
        }

        mv.addObject("codeType", codeTypeParse.getCodeType(file.getName()));
        mv.addObject("code", fpr.getCode());
        mv.addObject("charSetError", fpr.isCharsetError());
        mv.addObject("title", file.getName());
        mv.addObject("charsetStr", charsetStr);

        return mv;
    }


    private static ModelAndView error(String message) {
        ModelAndView mv = new ModelAndView();
        mv.setStatus(HttpStatus.NOT_FOUND);
        mv.setViewName("404");
        mv.addObject("message", message);
        return mv;
    }

    private boolean isAuth(String secretKey) {
        if ("".equals(autoSecretKey)) {
            return true;
        }
        return autoSecretKey == null || autoSecretKey.equals(secretKey);
    }

    @PostMapping("/push-recycle")
    public R pushRecycle(@RequestBody PathModel model) {
        if (!isAuth(model.getSecretKey())) {
            return R.err("请先获取权限");
        }
        if (Strings.isBlank(model.getPath())) {
            return R.err("path不能为空");
        }
        if (recycleService.existsFile(model.getPath())) {
            return R.err("文件已经在回收站中");
        }
        Path path = Paths.get(basePath, model.getPath());
        return recycleService.addRecycle(path.toString(), model.getPath());
    }


    @GetMapping("/recycle-list")
    public R recycleList() {
        return R.success(recycleService.getList().stream()
                .map(RecycleFileModel::toVo)
                .sorted((a, b) -> Math.toIntExact(b.getDeleteAt() - a.getDeleteAt()))
                .toList());
    }

    @PostMapping("/recycle-recovery")
    public R recycleRecovery(@RequestBody PathModel model) {
        if (!isAuth(model.getSecretKey())) {
            return R.err("请先获取权限");
        }
        if (Strings.isBlank(model.getPath())) {
            return R.err("path不能为空");
        }
        if (!recycleService.existsFile(model.getPath())) {
            return R.err("文件不在回收站中");
        }
        return recycleService.withdrawFile(model.getPath());
    }


    @PostMapping("/login")
    private R userLogin(@RequestBody UserLoginModel model) {
        String secretKey = model.getSecretKey();
        if (secretKey == null) {
            return R.err(("SecretKey不能为null"));
        }
        if (secretKey.equals(autoSecretKey)) {
            return R.success("认证成功");
        }
        return R.err("认证失败");

    }
}
